using UnityEngine;
using System.Collections;
using System.Runtime.Serialization;

[ExecuteInEditMode]
public class lwAstarNode : MonoBehaviour
{
	private static float DefaultComputeHeuristic(lwAstarNode from, lwAstarNode to)
	{
		Vector3 delta = from.transform.position - to.transform.position;
		return delta.magnitude;
	}

	public delegate void PassedDelegate(lwAstarNode node, lwAstarWalker walker);
	public delegate float Heuristic(lwAstarNode from, lwAstarNode to);
	public static Heuristic ComputeHeuristic = DefaultComputeHeuristic;
	public PassedDelegate NodePassed = null;

	[System.Serializable]
	public class lwAstarLink// : ISerializable
	{
		[SerializeField]
		public int m_destIndex;
		private lwAstarNode m_dest;
		public lwAstarNode dest
		{
			get
			{
				if (m_dest == null && lwAstarGraph.Instance != null )
				{
					m_dest = lwAstarGraph.Instance.GetNode(m_destIndex);
				}
				return m_dest;
			}
			set
			{
				if ( value != null )
				{
					m_destIndex = value.index;
					m_dest = value;
				}
				else
				{
					m_destIndex = -1;
					Debug.LogError("invalid link destination affectation");
					Debug.Break();
				}
			}
		}
		public float cost;
		public float costMultiplier;
		public float weight;
		public float weightMultiplier;

		public lwAstarLink(lwAstarNode dest)
		{
			m_dest = dest;
			if ( dest != null )
				m_destIndex = dest.index;
			cost = 0;
			weight = 1;
			costMultiplier = 1;
			weightMultiplier = 0;
		}

		public void UpdateLink(lwAstarNode source)
		{
			if(m_dest!=null)
			{
				if(source!=null)
				{
					cost = lwAstarNode.ComputeHeuristic(source, m_dest);
				}
				m_destIndex = m_dest.index;
			}
		}
		
#if UNITY_EDITOR
		public void UpdateLinkRef()
		{
			lwAstarGraph.Instance.RebuildNodeList();
			m_dest = lwAstarGraph.Instance.GetNode(m_destIndex);
		}
#endif
		
		//public lwAstarLink(SerializationInfo info, StreamingContext context) 
		//{
		//    m_destIndex = info.GetInt32("destIndex");
		//    if (m_destIndex != -1)
		//    {
		//        Debug.Log("m_destIndex unserialization success");
		//        m_dest = lwAstarGraph.Instance.GetNode(m_destIndex);
		//    }
		//    else
		//    {
		//        Debug.LogError("m_destIndex unserialization FAILED !!!");
		//        m_dest = null;
		//    }
		//    cost = (float)info.GetDouble("cost");
		//    weight = (float)info.GetDouble("weight");
		//}
		//public void GetObjectData(SerializationInfo info, StreamingContext context)
		//{
		//    info.AddValue("destIndex", m_destIndex);
		//    info.AddValue("cost", cost);
		//    info.AddValue("weight", weight);
		//}
	}

	[SerializeField]
	private int m_index = -1;
	public int index
	{
		get
		{
			return m_index;
		}
		set
		{
			m_index = value;
		}
	}
	
	public lwAstarLink[] m_Links = null;
	public float WeightedGlobalCost = 0;
	public float GlobalCost = 0;
	public float RemainingHeuristicCost = 0;
	public bool blocked = false;
	public Color colKevin = Color.red;
	public float TotalEstimatedCost
	{
		get { return WeightedGlobalCost + RemainingHeuristicCost; }
	}

	public lwAstarNode Parent = null;

	public lwAstarLink GetLinkTo(lwAstarNode dest)
	{
		foreach(lwAstarLink link in m_Links)
		{
			if(link.dest == dest)
			{
				return link;
			}
		}
		Debug.LogError("GetLinkTo Error : no link between nodes!");
		Debug.Break();
		return new lwAstarLink(dest);
	}

#if UNITY_EDITOR
	static private float m_GizmoSize = 10;
	static public float GizmoSize { get { return m_GizmoSize; }}
	private bool bHighLight = false;
	public bool m_bHighLight
	{
		get { return bHighLight; }
		set { bHighLight = value; }
	}
	
	void OnDrawGizmos()
	{
		if (m_bHighLight)
			Gizmos.color = Color.yellow;
		else
		{
			Gizmos.color = colKevin;
		}
		Gizmos.DrawCube(transform.position, Vector3.one * GizmoSize);


		Gizmos.color = Color.green;
		if (m_Links != null)
		{
			foreach (lwAstarLink link in m_Links)
			{
				if ( link.dest != null )
				{
					Vector3 unitDir = (link.dest.transform.position - this.transform.position).normalized;
					Gizmos.DrawCube(link.dest.transform.position - (GizmoSize * unitDir), Vector3.one * 2.0f);
				}
			}
		}
	}

	public delegate void OnDestroyDelegate(lwAstarNode node);
	public OnDestroyDelegate destroyDelegate = null;
	
	void OnDestroy()
	{
		if(!Application.isPlaying && destroyDelegate != null)
		{
			destroyDelegate(this);
		}
	}
	
#endif

}
